﻿using System;
using CamlQueryCreator.Tests.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CamlQueryCreator.Tests
{
    [TestClass]
    public class UnitTest1
    {
        #region Constants

        private const string TEST_WHERE_EQ_FORMAT = "<Where><Eq><FieldRef Name='{1}'/><Value Type='{2}'>{0}</Value></Eq></Where>";
        private const string TEST_WHERE_LEQ_FORMAT = "<Where><Leq><FieldRef Name='{1}'/><Value Type='{2}'>{0}</Value></Leq></Where>";
        private const string TEST_WHERE_IS_NOT_NULL_FORMAT = "<Where><IsNotNull><FieldRef Name='{0}'/></IsNotNull></Where>";
        private const string TEST_WHERE_AND_FORMAT = "<Where><And><Eq><FieldRef Name='{0}'/><Value Type='{1}'>{2}</Value></Eq><Eq><FieldRef Name='{3}'/><Value Type='{4}'>{5}</Value></Eq></And></Where>";
        /// <summary>
        /// Field_3 value must be integer;
        /// </summary>
        private const string TEST_WHERE_AND_AND_FORMAT = "<Where><And><And><Eq><FieldRef Name='{0}'/><Value Type='{1}'>{2}</Value></Eq><Eq><FieldRef Name='{3}'/><Value Type='{4}'>{5}</Value></Eq></And><Eq><FieldRef Name='{6}' LookupId='TRUE'/><Value Type='{7}'>{8}</Value></Eq></And></Where>";
        private const string TEST_ORDER_BY_FORMAT = "<OrderBy><FieldRef Name='{0}'/></OrderBy>";
        private const string TEST_ORDER_BY_AND_ORDER_BY_FORMAT = "<OrderBy><FieldRef Name='{0}'/><FieldRef Name='{1}'/></OrderBy>";
        private const string TEST_WHERE_AND_ORDER_BY_FORMAT = "<OrderBy><FieldRef Name='{0}'/></OrderBy><Where><Eq><FieldRef Name='{1}'/><Value Type='{2}'>{3}</Value></Eq></Where>";

        private const string VALUE_1 = "Value1";
        private const string VALUE_2 = "Value2";
        private const int VALUE_3 = 100;

        #endregion

        public FieldsData Fields = new FieldsData();

        [TestMethod]
        public void TestBase()
        {
            var query = Caml.GetQuery();

            if (!string.IsNullOrEmpty(query))
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhere()
        {
            var query = Caml.GetQuery(b => b.Where());

            if (!string.IsNullOrEmpty(query))
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhereEqNull()
        {
            var f = Fields.TextField1;
            var query = Caml.GetQuery(b => b.Where().Eq(f, null));

            if (!string.IsNullOrEmpty(query))
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhereEq()
        {
            var f = Fields.TextField1;
            var originalQuery = string.Format(TEST_WHERE_EQ_FORMAT, VALUE_1, f.Name, f.CamlQueryFieldType);

            var query = Caml.GetQuery(b => b.Where().Eq(f, VALUE_1));

            if (originalQuery != query)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhereBooleanEq()
        {
            Action<bool> testMethod =
                testValue =>
                    {
                        var f = Fields.BooleanField;


                        var query = Caml.GetQuery(b => b.Where().Eq(f, testValue));
                        var originalQuery = string.Format(TEST_WHERE_EQ_FORMAT,
                                                          testValue ? 1 : 0,
                                                          f.Name, f.CamlQueryFieldType);
                        if (query != originalQuery)
                            throw new InternalTestFailureException(string.Format("test for \"{0}\"-value", testValue));
                    };
            testMethod(true);
            testMethod(false);
        }

        [TestMethod]
        public void TestWhereLeq()
        {
            var f = Fields.TextField1;
            var originalQuery = string.Format(TEST_WHERE_LEQ_FORMAT, VALUE_1, f.Name, f.CamlQueryFieldType);

            var query = Caml.GetQuery(b => b.Where().Leq(f, VALUE_1));

            if (originalQuery != query)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhereIsNotNull()
        {
            var f = Fields.TextField1;
            var originalQuery = string.Format(TEST_WHERE_IS_NOT_NULL_FORMAT, f.Name);

            var query = Caml.GetQuery(b => b.Where().IsNotNull(f));

            if (originalQuery != query)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhereAnd()
        {
            var f1 = Fields.TextField1;
            var f2 = Fields.TextField2;
            var originalQuery = string.Format(TEST_WHERE_AND_FORMAT,
                                              f1.Name, f1.CamlQueryFieldType, VALUE_1,
                                              f2.Name, f2.CamlQueryFieldType, VALUE_2);

            var query = Caml.GetQuery(
                b => b.Where()
                         .And(i => i.Eq(f1, VALUE_1),
                              i => i.Eq(f2, VALUE_2)));

            if (originalQuery != query)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhereAndAnd()
        {
            var f1 = Fields.TextField1;
            var f2 = Fields.TextField2;
            var f3 = Fields.UserField;
            var originalQuery = string.Format(TEST_WHERE_AND_AND_FORMAT,
                                              f1.Name, f1.CamlQueryFieldType, VALUE_1,
                                              f2.Name, f2.CamlQueryFieldType, VALUE_2,
                                              f3.Name, f3.CamlQueryFieldType, VALUE_3);

            var query = Caml.GetQuery(
                b => b.Where()
                         .And(i => i.And(j => j.Eq(f1, VALUE_1),
                                         j => j.Eq(f2, VALUE_2)),
                              i => i.Eq(f3, VALUE_3)));

            if (originalQuery != query)
                throw new InternalTestFailureException(string.Format("{0}\nis not\n{1}", originalQuery, query));
        }

        [TestMethod]
        public void TestOrderBy()
        {
            var f = Fields.TextField1;
            var originalQuery = string.Format(TEST_ORDER_BY_FORMAT, f.Name);

            var query = Caml.GetQuery(b => b.OrderBy(f));

            if (originalQuery != query)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestOrderByAndOrderBy()
        {
            var f1 = Fields.TextField1;
            var f2 = Fields.TextField2;
            var originalQuery = string.Format(TEST_ORDER_BY_AND_ORDER_BY_FORMAT, f1.Name, f2.Name);

            var query = Caml.GetQuery(
                b =>
                b.OrderBy(f1)
                    .AndOrderBy(f2));

            if (originalQuery != query)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestWhereAndOrderBy()
        {
            var f1 = Fields.TextField1;
            var f2 = Fields.TextField2;
            var originalQuery = string.Format(TEST_WHERE_AND_ORDER_BY_FORMAT, f2.Name, f1.Name, f1.CamlQueryFieldType, VALUE_1);

            var query = Caml.GetQuery(
                b => b.Where().Eq(f1, VALUE_1),
                b => b.OrderBy(f2));

            if (originalQuery != query)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestOrderByAndWhere()
        {
            var f1 = Fields.TextField1;
            var f2 = Fields.TextField2;

            var query1 = Caml.GetQuery(
                b => b.Where().Eq(f1, VALUE_1),
                b => b.OrderBy(f2));

            var query2 = Caml.GetQuery(
                b => b.OrderBy(f2),
                b => b.Where().Eq(f1, VALUE_1));

            if (query1 != query2)
                throw new InternalTestFailureException();
        }

        [TestMethod]
        public void TestFieldInfoAndFieldName()
        {
            const string userFieldName = "UserField";
            const string textFieldName1 = "TextField1";
            const string textFieldName2 = "TextField2";
            const string integerFieldName = "IntegerField";

            const string textValue1 = "TextValue1";
            const string textValue2 = "TextValue2";
            const int integerValue = 100;

            var queryText1 = Caml.GetQuery(
                builder => builder
                               .Where()
                               .And(i => i.And(j => j.CurrentUserEq(userFieldName),
                                               j => j.Eq(textFieldName1, FieldTypeKind.Text, textValue1)),
                                    i => i.Or(j => j.Eq(integerFieldName, FieldTypeKind.Integer, integerValue),
                                              j => j.Eq(textFieldName2, FieldTypeKind.Text, textValue2))),
                builder => builder
                               .OrderBy(textFieldName1)
                               .AndOrderBy(integerFieldName));

            var userFieldInfo = new ListFieldInfo(userFieldName, FieldTypeKind.User);
            var textFieldInfo1 = new ListFieldInfo(textFieldName1, FieldTypeKind.Text);
            var textFieldInfo2 = new ListFieldInfo(textFieldName2, FieldTypeKind.Text);
            var integerFieldInfo = new ListFieldInfo(integerFieldName, FieldTypeKind.Integer);

            var queryText2 = Caml.GetQuery(
                builder => builder
                               .Where()
                               .And(i => i.And(j => j.CurrentUserEq(userFieldInfo),
                                               j => j.Eq(textFieldInfo1, textValue1)),
                                    i => i.Or(j => j.Eq(integerFieldInfo, integerValue),
                                              j => j.Eq(textFieldInfo2, textValue2))),
                builder => builder
                               .OrderBy(textFieldInfo1)
                               .AndOrderBy(integerFieldInfo));

            if (queryText1 != queryText2)
                throw new InternalTestFailureException();
        }
    }
}
